home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Atari Mega Archive 1
/
Atari Mega Archive - Volume 1.iso
/
language
/
examples.zoo
/
misc
/
gruppen.lsp
< prev
next >
Wrap
Lisp/Scheme
|
1991-10-22
|
50KB
|
1,233 lines
; Behandlung von Gruppentheorie
; insbesondere Schreier-Sims-Algorithmus und Rubik's Cube-Gruppe
; außerdem Reduktion der Erzeugenden-Wort-Längen
; Bruno Haible, November-Dezember 1987
#+VAX
(setq f "gruppen.lsp")
#+VAX
(defun c ()
(compile-file "gruppen.lsp" :output-file "gruppen.fas" :listing t)
)
(defvar *gruppen-trace* t)
; gibt an, ob kurze Meldungen auf dem Bildschirm erscheinen
; (intlist a b) ergibt (a a+1 ... b-1 b), wenn a und b integers sind.
(proclaim '(function intlist (integer integer) list))
(defun intlist (a b)
(do ((l nil (cons i l))
(i b (1- i)))
((< i a) l)
) )
; (list-rotate '(a1 a2 ... an)) ergibt '(a2 ... an a1)
(proclaim '(function list-rotate (list) list))
(defun list-rotate (l)
(append (rest l) (list (first l)))
)
; (search-min sequence predicate &key :key :default :from-end) sucht in einer
; Folge nach einem minimalen Element. (predicate x y) gibt an, wann x<y sein
; soll. :key ist eine Funktion, die aus jedem Element der Folge die zu
; vegleichende Größe bildet. :default ist der Wert, der sich bei der leeren
; Folge ergibt. Die Suche geschieht von links nach rechts und liefert das am
; weitesten links gelegene Minimum, bei :from-end t umgekehrt.
; Der erste Wert ist der Minimalwert, der zweite das fragliche Folgenelement.
(defun search-min (seq pr &key (key #'identity) (default nil) (from-end nil)
&aux mel)
(if from-end (setq seq (reverse seq)))
(if (zerop (length seq))
default
(values (reduce #'(lambda (bisher-min el &aux (k (funcall key el)))
(cond ((funcall pr k bisher-min)
(setq mel el) k)
(t bisher-min)
) )
seq
:start 1
:initial-value (funcall key (setq mel (elt seq 0)))
)
mel
) ) )
;-------------------------------------------------------------------------------
; Die gerade aktuelle Gruppe (Defaultwert)
(defvar *pgruppe*)
;-------------------------------------------------------------------------------
; Datentyp der Permutation:
; (injektiv a) stellt fest, ob eine Abbildung a (ein Array) injektiv ist
; und eine Permutation der Zahlen ab 1 aufwärts ist.
(proclaim '(function injektiv (vector) atom))
(defun injektiv (a)
(equal (sort (coerce a 'list) #'<) (intlist 1 (length a)))
)
(deftype Mn (&optional n)
"Mn ist die Menge {1,...,n}"
; `(integer (1) (,n)) gemeint
(declare (ignore n))
'integer
)
(deftype perm (&optional n)
"PERM ist eine Permutation, als Abbildung dargestellt."
; `(and (array (Mn ,n) (,n)) (satisfies injektiv)) gemeint
(declare (ignore n))
`(and (array t (*)) (satisfies injektiv))
)
; Operationen auf Permutationen:
; Anwendung einer Permutation auf eine Zahl
(defmacro apply-perm (s i)
`(aref ,s (1- ,i))
)
; Aufbauen einer Permutation aus einer Liste l mit n Elementen
(proclaim '(function make-perm (list) perm))
(defun make-perm (l)
(let* ((n (length l))
(u (make-array `(,n) :element-type `(Mn ,n) )))
(do ((i 1 (1+ i))
(l l (cdr l)))
((null l))
(setf (apply-perm u i) (car l))
)
(if (not (injektiv u)) (error "~S ist keine Permutation." u))
u
) )
; Multiplikation zweier Permutationen: s nach t
(proclaim '(function perm* (perm perm) perm))
(defun perm* (s1 t1)
(let* ((n (length t1))
(u (make-array `(,n) :element-type `(Mn ,n) )))
(do ((i 1 (+ i 1)))
((> i n))
(setf (apply-perm u i) (apply-perm s1 (apply-perm t1 i)))
)
u
) )
; Invertieren einer Permutation
(proclaim '(function perm/ (perm) perm))
(defun perm/ (s)
(let* ((n (length s))
(u (make-array `(,n) :element-type `(Mn ,n))))
(do ((i 1 (1+ i)))
((> i n))
(setf (apply-perm u (apply-perm s i)) i)
)
u
) )
; neutrales Element (identische Abbildung)
(proclaim '(function perm-id (&optional integer) perm))
(defun perm-id (&optional (n (pgruppe-grad *pgruppe*)))
(let ((u (make-array `(,n) :element-type `(Mn ,n))))
(do ((i 1 (1+ i)))
((> i n))
(setf (apply-perm u i) i)
)
u
) )
; Test auf neutrales Element
(proclaim '(function perm-id-p (perm &optional integer) atom))
(defun perm-id-p (p &optional (n (length p)))
(do ((i 1 (1+ i)))
((> i n) t)
(unless (= (apply-perm p i) i) (return-from perm-id-p nil))
) )
; erzeugt eine Permutation aus ihrer Zyklendarstellung
; Permutation auf {1,...,n}, gegeben als Liste elementfremder Zyklen
(proclaim '(function zykl-perm (list integer) perm))
(defun zykl-perm (zl n)
(let ((u (perm-id n)))
(dolist (z zl)
(setf (apply-perm u (car (last z))) (first z))
(do ((l z (cdr l)))
((endp (cdr l)))
(setf (apply-perm u (first l)) (second l))
) )
(the perm u)
) )
; erzeugt die Zyklendarstellung einer Permutation
(proclaim '(function perm-zykl (perm) list))
(defun perm-zykl (p)
(let ((n (length p)))
(do ((i 1 (1+ i))
(zl nil) ; Zyklenliste
(p1 (copy-seq p))) ; verändertes p
((> i n) (nreverse zl))
; Suche, ob bei i ein Zyklus anfängt
(unless (= (apply-perm p1 i) i)
(push (do ((j i)
(z nil) ; Zyklus
(flag nil t))
((and flag (= j i)) (nreverse z))
(push j z)
(rotatef (apply-perm p1 j) j)
; neues (apply-perm p1 j) := j,
; neues j := altes (apply-perm p1 j)
)
zl
) )
) ) )
;-------------------------------------------------------------------------------
; Datentyp des benannten Erzeugendensystems
; Ein benanntes Erzeugendensystem ist eine Ansammlung von Permutationen, von
; denen jede einen Namem hat. Auf sie wird mit (aref1 ezs i) verwiesen.
(deftype named-erz-sys (&optional n)
"ERZ-SYS ist eine Erzeugendensystem aus der Sn."
; `(array (cons (perm ,n) string) (*)) gemeint
(declare (ignore n))
'vector
)
; (aref1 s i) ergibt allgemein das i-te Element (i=1,2,...) eines Arrays s.
(defmacro aref1 (s i)
`(aref ,s (1- ,i))
)
; Aufbauen eines Erzeugendensystems aus einer Liste l von Permutationen
(defun make-erz-sys (l)
(coerce (mapcar #'(lambda (p) (cons p "")) l) 'vector))
;-------------------------------------------------------------------------------
; Datentyp des Erzeugendenprodukts:
; In Bezug auf ein festes Erzeugendensystem ezs mit m Elementen:
; Die Erzeugenden werden durchnumeriert: 1,...,m für die angegebenen,
; -1,...,-m für ihre Inversen.
; Nun bedeutet ein Erzeugendenprodukt ezp = (t1 ... tk) das Produkt
; Et1 * .... * Etk.
(deftype ezp () 'list)
; Multiplikation zweier Erzeugendendarstellungen: s nach t
; An der Nahtstelle werden Inverse bereits zusammengefaßt.
(proclaim '(function ezp* (ezp ezp) ezp))
(defun ezp* (s1 t1)
(do ((l1 (reverse s1) (cdr l1))
(l2 t1 (cdr l2)))
((or (null l1) (null l2) (not (zerop (+ (car l1) (car l2)))))
(nreconc l1 l2))
) )
; Invertieren einer Erzeugendendarstellung
(proclaim '(function ezp/ (ezp) ezp))
(defun ezp/ (s)
(nreverse (mapcar #'- s)))
; Ausgeben eines Erzeugendenprodukts mit Hilfe eines benannten Erzeugenden-
; systems.
(defun ezp-print (s nezs &optional (stream *standard-output*))
(if (null s)
(princ '"Id" stream)
(do ((l s))
((endp l))
(let ((i (pop l)))
(princ (cdr (aref1 nezs (abs i))) stream)
(if (minusp i) (princ '"^-1" stream))
)
(unless (endp l) (princ '" * " stream))
) ) )
(defconstant uses-ezprt nil "Wird eine Erzeugendenprodukttabelle verwendet?")
; Um Erzeugendendarstellungen weiter vereinfachen zu können, brauchen wir
; eine Tabelle, die uns z.B. sagt, daß wir (5 -3 -4) zu (6) und somit auch
; (7 5 -3 -4 -6) zu (7 6 -6) und dann zu (7) vereinfachen können.
; Datentyp einer Erzeugendenprodukt-Red